package org.zjvis.datascience.service.csv.postgresql;

import com.google.common.base.Preconditions;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.zjvis.datascience.service.csv.ColumnType;

import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class PostgresqlTableCreator {
    private String tableName;
    private List<String> columnNameList;
    private List<ColumnType> columnTypeList;
    @Builder.Default
    private boolean addRecordIdIndex = false;
    @Builder.Default
    private String indexName = "_record_id_";

    public List<String> columnNameListOfTable(){
        return Stream.concat(
                addRecordIdIndex ? Stream.of(indexName): Stream.empty(),
                columnNameList.stream()
        ).collect(Collectors.toList());
    }
    public List<String> columnTypeListOfTable(){
        return Stream.concat(
                addRecordIdIndex ? Stream.of(ColumnType.INTEGER): Stream.empty(),
                columnTypeList.stream()
        ).map(columnType -> {
            switch (columnType){
                case INTEGER:
                    return "integer";
                case STRING:
                    return "varchar";
                case DOUBLE:
                    return "float4";
                case LOCAL_DATE_TIME:
                    return "date";
                default:
                    throw new RuntimeException(String.format("columnType(%s) not support", columnType));
            }
        }).collect(Collectors.toList());
    }

    public String dropTableIfExistsSql() {
        return String.format("drop table if exists %s", tableName);
    }

    public String createTableIfNotExistsSql() {
        Preconditions.checkArgument(columnNameList.size() == columnTypeList.size(),
                "size of columnNameList(%s) != size of columnTypeList(%s)",
                columnNameList.size(), columnTypeList.size());
        String columnDefinition = IntStream.range(0, columnNameList.size())
                .boxed()
                .map(index -> String.format(
                        "\"%s\" %s",
                        columnNameList.get(index),
                        databaseType(columnTypeList.get(index))))
                .collect(Collectors.joining(", "));
        return String.format(
                "create table IF NOT EXISTS %s(%s%s)",
                tableName,
                addRecordIdIndex ? String.format("\"%s\" SERIAL, ", indexName) : "",
                columnDefinition
        );
    }

    private String databaseType(ColumnType columnType) {
        switch (columnType) {
            case DOUBLE:
                return "float4";
            case INTEGER:
                return "integer";
            case STRING:
                return "varchar";
            case LOCAL_DATE_TIME:
                return "date";
            default:
                throw new RuntimeException(String.format("columnType(%s) not support", columnType));
        }
    }
}
